#include "FeatureResponse.h"
#include "./Classifier.h"
#include "./SVMClassifier.h"
#include <math.h>
#include <stdio.h>
#include <sys/time.h>
#include <iostream>
#include <time.h>
#include <fstream>
#include <stdlib.h>
#include "./BoostedClassifierIV.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

namespace findobject{
using namespace std;
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int current_nr_threads = 0;
int max_threads	  = 5;
int portno 		  = 51515;
char * data_adr;
char * ip_adr		  = (char *)"130.237.218.108";//"127.0.0.1";

float ** all_responses = 0;


float estimate_error(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns);
float * estimate_error_gradient_faster(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns);
float * estimate_error_gradient(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns);
float gradient_decent_optimize(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns);
void * gdo( void *ptr );
int my_new_thread(float * output_place, char * datapath ,/*int nr_responses,*/ int * added_columns, float * alpha, int nr_columns);
void error(const char *msg);
void client_return_findings(int index, float value);
void * client_thread( void *ptr );

float estimate_error(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns)
{
	float error = 0;
	for(int i = 0; i < nr_responses; i++)
	{
		float val = responses[0][i];
		float val2 = 0;
		for(int j = 0; j < nr_columns; j++)
		{
			val2 += responses[added_columns[j]][i] * alpha[j];
		}
		if(val == 0)
		{
			if(val2 > 0)
			{
				error += val2*val2;
			}
		}
		else
		{
			error += (val-val2)*(val-val2);
		}
	}
	//usleep(2000);
	return error;
}

float * estimate_error_gradient_faster(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns)
{
	float * base = new float[nr_responses];
	float * trouth = responses[0];

	float norm_factor = 0;
	for(int i = 0; i < nr_responses; i++)
	{
		float val2 = 0;
		for(int j = 0; j < nr_columns; j++)
		{
			val2 += responses[added_columns[j]][i] * alpha[j];
		}
		base[i] = trouth[i]-val2;
	}
	float small_number = 0.0001;
	float * gradient  = new float[nr_columns];
	for(int i = 0; i < nr_columns; i++)
	{
		gradient[i] = 0;
	}

	for(int j = 0; j < nr_columns; j++)
	{
		double error_plus  = 0;
		double error_minus = 0;

		float * this_col  = responses[added_columns[j]];
		double val_plus;
		double val_minus;


		for(int i = 0; i < nr_responses; i++)
		{
			val_plus  = base[i]-(small_number*this_col[i]);
			val_minus = base[i]+(small_number*this_col[i]);
			if(trouth[i] == 0)
			{
				if(val_plus < 0)
				{
					error_plus += val_plus * val_plus;
				}
				if(val_minus< 0)
				{
					error_minus+= val_minus*val_minus;
				}

			}
			else{
				error_plus += val_plus * val_plus;
				error_minus+= val_minus*val_minus;
			}
		}
		float this_grad= -(error_plus-error_minus)/(small_number * 2);
		gradient[j] = this_grad;
		norm_factor+= gradient[j]*gradient[j];
	}
	delete base;

	norm_factor = pow(norm_factor,0.5f);
	for(int i = 0; i < nr_columns; i++)
	{
		gradient[i] /= norm_factor;
		if(norm_factor == 0){gradient[i] = 0;}
	}
	return gradient;
}

float * estimate_error_gradient(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns)
{
	float small_number = 0.0001;
	float * gradient  = new float[nr_columns];
	float * alpha_tmp = new float[nr_columns];
	float norm_factor = 0;
	for(int i = 0; i < nr_columns; i++)
	{
		gradient[i] = 0;
		for(int j = 0; j < nr_columns; j++)
		{
			alpha_tmp[j]=alpha[j];
		}
		alpha_tmp[i] -= small_number;
		float err1 = estimate_error(responses,nr_responses,added_columns,alpha_tmp,nr_columns);
		alpha_tmp[i] += 2*small_number;
		float err2 = estimate_error(responses,nr_responses,added_columns,alpha_tmp,nr_columns);
		gradient[i] =  (err1-err2)/(2*small_number);
		norm_factor+= gradient[i]*gradient[i];
	}
	delete alpha_tmp;
	norm_factor = pow(norm_factor,0.5f);
	for(int i = 0; i < nr_columns; i++)
	{
		gradient[i] /= norm_factor;
		if(norm_factor == 0){
			gradient[i] = 0;
		}
	}
	return gradient;
}

float gradient_decent_optimize(float ** responses,int nr_responses, int * added_columns, float * alpha, int nr_columns)
{
	float stepwidth = 0.1f;
	float last_err = 999999;
	for(int i = 0; i < 150; i++)
	{
		float err 	= estimate_error(responses,nr_responses, added_columns, alpha, nr_columns);
		//printf("err: %f\n",err);
		if(fabs(err-last_err) < 0.1f ){/*printf("broke at %i\n",i);*/break;}
		last_err = err;
		float * grad = estimate_error_gradient_faster(responses,nr_responses, added_columns, alpha, nr_columns);
		for(int j = 0; j < nr_columns; j++){alpha[j]+=grad[j]*stepwidth;}
		stepwidth*=0.98;
		delete grad;
	}

	return estimate_error(responses,nr_responses, added_columns, alpha, nr_columns);
}

pthread_mutex_t clear_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t client_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t * clear_threads = 0;
int nr_clear_threads = 0;
void *** input_to_delete = 0;


void * gdo( void *ptr )
{
	//sleep(4);
	void ** tmp_input 		= (void **)ptr;
	float * output_ptr		= (float *)tmp_input[0];
	int nr_responses 		= (int)tmp_input[1];
	int nr_columns   		= (int)tmp_input[2];
	char ** datapath_ptr 		= (char **)tmp_input[3];
	int * added_columns 		= new int[nr_columns];
	int * tmp_added_columns 	= new int[nr_columns];
	float * alpha 			= new float[nr_columns];
	//printf("nr_responses = %i, nr_columns = %i\n",nr_responses,nr_columns);
	for(int i = 0; i < nr_columns; i++)
	{
		//printf("Fake:tmp_added_columns[%i] = %i\n",i,tmp_added_columns[i]);
		added_columns[i] 		=(int)tmp_input[4+i];
		tmp_added_columns[i]		=i+1;
		alpha[i] 			=0;//(float)tmp_input[4+i+nr_columns];
	}
	float ** responses = new float*[nr_columns+1];
	{
		bool ok = false;
		while(!ok){
			char filename_bin[256];
			sprintf(filename_bin, "%s_%i.results",data_adr, 0);
			//printf("opened %s \n",filename_bin);
			//responses[0] = new float[nr_responses];
			ifstream::pos_type fsize_bin;
			ifstream file_bin (filename_bin, ios::in|ios::binary|ios::ate);
			if (file_bin.is_open())
			{
				ok = true;
				fsize_bin = file_bin.tellg();
				nr_responses = (int)(fsize_bin/4);
				responses[0] = new float[nr_responses];
				file_bin.seekg (0, ios::beg);
				file_bin.read ((char *)responses[0], fsize_bin);
				file_bin.close();
			}
			else{
				printf("couldnt open %s \n",filename_bin);
				printf("data_adr = %s\n",data_adr);
				sleep(1);
			}
		}
	}
	for(int i = 0; i < nr_columns;i++)
	{
		bool ok = false;
		while(!ok){
			char filename_bin[256];
			sprintf(filename_bin, "%s_%i.results",data_adr, added_columns[i]);
			//printf("opened %s \n",filename_bin);
			//responses[i+1] = new float[nr_responses];
			ifstream::pos_type fsize_bin;
			ifstream file_bin (filename_bin, ios::in|ios::binary|ios::ate);
			if (file_bin.is_open())
			{
				ok = true;
				fsize_bin = file_bin.tellg();
				responses[i+1] = new float[nr_responses];
				file_bin.seekg (0, ios::beg);
				file_bin.read ((char *)responses[i+1], fsize_bin);
				file_bin.close();
			}
			else{
				printf("couldnt open %s \n",filename_bin);
				printf("data_adr = %s\n",data_adr);
				sleep(1);
			}
		}
	}
	float ans = gradient_decent_optimize(responses,nr_responses, tmp_added_columns, alpha, nr_columns);
	*output_ptr = ans;
	//printf("ans=%i:%f\n",added_columns[nr_columns-1],ans);
	client_return_findings(added_columns[nr_columns-1], ans);
	for(int i = 0; i < nr_columns+1;i++)
	{
		delete[] responses[i];
	}
	delete[] responses;
	delete[] added_columns;
	delete[] tmp_added_columns;
	delete[] alpha;
	pthread_mutex_lock( &mutex1 );
	current_nr_threads--;
	pthread_mutex_unlock( &mutex1 );
	pthread_mutex_lock( &clear_mutex);
	pthread_t id = pthread_self();
	clear_threads[nr_clear_threads] = id;
	input_to_delete[nr_clear_threads] = tmp_input;
	nr_clear_threads++;
	pthread_mutex_unlock( &clear_mutex);

}

int my_new_thread(float * output_place, char * datapath ,/*int nr_responses,*/ int * added_columns, float * alpha, int nr_columns){
	pthread_t thread1;
	void ** tmp_input = new void*[4+2*nr_columns];
	tmp_input[0] = (void *)output_place;
	//tmp_input[1] = (void *)nr_responses;
	tmp_input[2] = (void *)nr_columns;
	tmp_input[3] = (void *)(&datapath);

	for(int i = 0; i < nr_columns; i++)
	{
		tmp_input[4+i] = (void *)(added_columns[i]);
		tmp_input[4+i+nr_columns] = 0;//(void *)(alpha[i]);
	}

	int iret1 = pthread_create( &thread1, NULL, gdo, (void*) tmp_input);
	return iret1;
}

BoostedClassifierIV::BoostedClassifierIV(char * filename) {
	load(filename);
}

void error(const char *msg)
{
	perror(msg);
	exit(1);
}

void client_return_findings(int index, float value)
{
pthread_mutex_lock( &client_mutex);
	int sockfd,/* portno,*/ n;
	struct sockaddr_in serv_addr;
	struct hostent *server;
	char buffer[256];
	//portno = 51515;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	while (sockfd < 0){
		sleep(1);
		printf("ERROR opening socket\n");
		sockfd = socket(AF_INET, SOCK_STREAM, 0);
	}
	server = gethostbyname(ip_adr);
	while (server == NULL) {
		sleep(1);
		server = gethostbyname(ip_adr);
		fprintf(stderr,"ERROR, no such host\n");
		//exit(0);
	}
	bzero((char *) &serv_addr, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	bcopy((char *)server->h_addr,
			(char *)&serv_addr.sin_addr.s_addr,
			server->h_length);
	serv_addr.sin_port = htons(portno);
	bool has_failed = false;
	int conncect_counter = 0;
	while (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
	{
		conncect_counter++;
		printf("ERROR connecting, conncect_counter = %i\n",conncect_counter);
		has_failed = true;
		sleep(2);
		if(conncect_counter > 100){
			exit(0);
		}
	}
	if(has_failed){printf("SUCCESFULL connecting\n");}
	//printf("Please enter the message: ");
	bzero(buffer,256);
	//fgets(buffer,255,stdin);
	float * command = new float[3];
	command[0] = 1;
	command[1] = index;
	command[2] = value;
	printf("Calculated: index = %i, value = %f\n",index,value);
	//memcpy(&(command[2]),&value,4);
	n = write(sockfd,command,12);
	delete command;
	if (n < 0)
		error("ERROR writing to socket");
	close(sockfd);
pthread_mutex_unlock( &client_mutex);
}

void * client_thread( void *ptr )
{
	while(true){
		bool unlocked = false;
		pthread_mutex_lock( &mutex1 );
		if(current_nr_threads < max_threads)
		{
			pthread_mutex_unlock( &mutex1 );
			unlocked = true;
			//printf("can accept thread\n");

			pthread_mutex_lock( &client_mutex);
			int sockfd, /*portno,*/ n;
			struct sockaddr_in serv_addr;
			struct hostent *server;

			char buffer[256];

			//portno = 51515;
			sockfd = socket(AF_INET, SOCK_STREAM, 0);
			if (sockfd < 0)
				error("ERROR opening socket");
			server = gethostbyname(ip_adr);
			if (server == NULL) {
				fprintf(stderr,"ERROR, no such host\n");
				exit(0);
			}
			bzero((char *) &serv_addr, sizeof(serv_addr));
			serv_addr.sin_family = AF_INET;
			bcopy((char *)server->h_addr,
					(char *)&serv_addr.sin_addr.s_addr,
					server->h_length);
			serv_addr.sin_port = htons(portno);
			int conncect_counter = 0;
			while (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
			{
				conncect_counter++;
				printf("ERROR connecting, conncect_counter = %i\n",conncect_counter);
				sleep(2);
				if(conncect_counter > 100){
					exit(0);
				}
			}
			//printf("Please enter the message: ");
			bzero(buffer,256);
			//fgets(buffer,255,stdin);
			int * command = new int[1];
			command[0] = 0;
			n = write(sockfd,command,4);
			delete command;
			if (n < 0)
				error("ERROR writing to socket");
			bzero(buffer,256);
			n = read(sockfd,buffer,255);
			if (n < 0)
				error("ERROR reading from socket");
			int * output = (int *)buffer;
			close(sockfd);
			pthread_mutex_unlock( &client_mutex);
			if(output[0]==1){
				//printf("server has no work for me atm\n");
				sleep(1);
			}
			else{
				int * added_columns = new int[(n/4)-1];
				float * alpha = new float[(n/4)-1];
				for(int i = 1; i < (n/4); i++)
				{
					added_columns[i-1] = output[i];
					alpha[i-1] = 0;
				}
				pthread_mutex_lock( &mutex1 );
				current_nr_threads++;
				pthread_mutex_unlock( &mutex1 );
				float * dummy = new float[1];
				int iret1 = my_new_thread(dummy,data_adr, added_columns, alpha, (n/4)-1);
				if(iret1 != 0){
					pthread_mutex_lock( &mutex1 );
					current_nr_threads--;
					pthread_mutex_unlock( &mutex1 );
					//TODO:tell server of failure.
					printf("cant create thread\n");
				}
				delete[] added_columns;
				delete[] alpha;
			}

		}
		if(!unlocked){pthread_mutex_unlock( &mutex1 );}
		usleep(1000);
		//Cleanup
		pthread_mutex_lock( &clear_mutex);
		for(int i = 0; i < nr_clear_threads; i++)
		{
			int rc = pthread_join((clear_threads[i]), NULL);
			if(rc){
				printf("ERROR; return code from pthread_join()is %d\n", rc);
				exit(-1);}
			delete[] input_to_delete[i];
			//client_return_findings(1337, 2.345f);
		}
		nr_clear_threads = 0;
		pthread_mutex_unlock( &clear_mutex);
	}
}


BoostedClassifierIV::BoostedClassifierIV(char * classifiers_path, char * responses_path, char * save_path, int nr_regressors_stop) {
printf("=================================1337==BoostedClassifierIV==================================\n");
	data_adr = responses_path;
	printf("|| classifiers_path   = %s\n",classifiers_path);
	printf("|| data_adr           = %s\n",data_adr);
	printf("|| save_path          = %s\n",save_path);
	printf("|| nr_regressors_stop = %i\n",nr_regressors_stop);

	clear_threads = new pthread_t[100000];
	input_to_delete = new void **[100000];
	nr_clear_threads = 0;
	//printf("setting up with classifiers_path = %s and responses_path = %s\n",classifiers_path,responses_path);
	bool loop = true;
	Classifier ** list_of_classifiers = new Classifier*[100000];
	int nr_of_patches = 0;
	for(int i = 0; loop ; i++)
	{
		Classifier * classifier = new SVMClassifier();
		char filename[256];
		sprintf(filename, "%s_%i",classifiers_path, i);
		//printf("loading %s\n",filename);
		loop = classifier->load(filename);
		if(loop)
		{
			list_of_classifiers[i] = classifier;
			nr_of_patches = i+1;
		}
		//else{printf("loaded all classifiers\n");}
	}
	classifiers = list_of_classifiers;
	char filename_base2[256];
	sprintf(filename_base2, "%s.base",responses_path);
	//printf("opening base at: %s\n",filename_base2);
	int output_base_size2 = 3;

	float * output_base2 = new float[output_base_size2];
	ifstream::pos_type fsize2;

	ifstream file_base2(filename_base2, ios::in|ios::binary|ios::ate);

	if (file_base2.is_open())
	{
		fsize2 = file_base2.tellg();
		file_base2.seekg (0, ios::beg);
		file_base2.read ((char *)output_base2, fsize2);
		file_base2.close();
	}else
	{
		printf("couldnt open base\n");
	}

	int classifier_responses_saved 	= output_base2[0];
	nr_of_patches 			= output_base2[1];
	float target_object_size		= output_base2[2];
	delete[] output_base2;
	printf("|| nr_of_responses  = %i\n",classifier_responses_saved);
	printf("|| nr_of_patches    = %i\n",nr_of_patches);
	printf("target_object_size = %f\n",target_object_size);
	float ** responses = new float*[nr_of_patches+1];
	{
		int i = 0;
		char filename_bin[256];
		sprintf(filename_bin, "%s_%i.results",responses_path, i);
		responses[i] = new float[classifier_responses_saved];
		ifstream::pos_type fsize_bin;
		ifstream file_bin (filename_bin, ios::in|ios::binary|ios::ate);
		if (file_bin.is_open())
		{
			fsize_bin = file_bin.tellg();
			file_bin.seekg (0, ios::beg);
			file_bin.read ((char *)responses[i], fsize_bin);
			file_bin.close();
		}
		else{printf("couldnt open %s \n",filename_bin);}
	}
	/*for(int i = 0; i < nr_of_patches+1;i++)
	{
		char filename_bin[256];
		sprintf(filename_bin, "%s_%i.results",responses_path, i);
		responses[i] = new float[classifier_responses_saved];
		ifstream::pos_type fsize_bin;
		ifstream file_bin (filename_bin, ios::in|ios::binary|ios::ate);
		if (file_bin.is_open())
		{
			fsize_bin = file_bin.tellg();
			file_bin.seekg (0, ios::beg);
			file_bin.read ((char *)responses[i], fsize_bin);
			file_bin.close();
		}
		else{printf("couldnt open %s \n",filename_bin);}
	}*/

	patch = 0;
	//int nr_patches_to_use = nr_of_patches/2;
	int * added_columns 	= new int[nr_of_patches+1];
	float * alpha 		= new float[nr_of_patches+1];
	classifiers = list_of_classifiers;
	alpha_weight = alpha;
	used_classifiers = added_columns;

	for(int i = 0; i < nr_of_patches; i++)
	{
		added_columns[i] = i+1;
		alpha[i] = 0;
	}
	int nr_columns = 0;

printf("===================================================================\n");

	pthread_t client_t;
	int iret_client = pthread_create( &client_t, NULL, client_thread, NULL);
	int sockfd, newsockfd/*, portno*/;
	socklen_t clilen;
	char buffer[256];
	struct sockaddr_in serv_addr, cli_addr;
	int n;
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	while(sockfd < 0){
		printf("ERROR opening socket\n");
		sleep(1);
		sockfd = socket(AF_INET, SOCK_STREAM, 0);
	}
	bzero((char *) &serv_addr, sizeof(serv_addr));
	//portno = 51515;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(portno);
	while (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0){
		printf("ERROR on binding\n");
		sleep(1);
	}
	while(nr_columns < nr_regressors_stop)
	{
		int current_to_do = 1;
		struct timeval start, end;
		gettimeofday(&start, NULL);
		float * all_results = new float[nr_of_patches+1];
		for(int i = 0; i < nr_of_patches+1; i++){all_results[i]=0;}
		int values_left_to_get = nr_of_patches;
		while(values_left_to_get > 0)
		{
			//printf("1\n");
			listen(sockfd,5);
			clilen = sizeof(cli_addr);
			newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
			while(newsockfd < 0){
				printf("ERROR on accept\n");
				sleep(1);
				newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
			}
			bzero(buffer,256);
			n = read(newsockfd,buffer,255);
			if (n < 0) error("ERROR reading from socket");
			int   * input_int = (int*)buffer;
			float * input_float = (float*)buffer;
			if((input_int[0] == 0) && (current_to_do < nr_of_patches+1)){//Client says it has atleast one free thread
				int * output = new int[2+nr_columns];
				output[0]=0;
				added_columns[nr_columns] = current_to_do;
				for(int i = 0; i <= nr_columns; i++){output[i+1]=added_columns[i];}
				n = write(newsockfd,output,4*(2+nr_columns));
				if (n < 0) error("ERROR writing to socket");
				current_to_do++;
				delete[] output;
			}else if(input_int[0] == 0){
				int * output = new int[1];
				output[0]=1;
				n = write(newsockfd,output,4);
				if (n < 0) error("ERROR writing to socket");
			}else if(input_float[0] == 1){//Client returns data
				int regressor_number = input_float[1];
				float regressor_value = input_float[2];
				all_results[regressor_number] = regressor_value;
				values_left_to_get--;
				gettimeofday(&end, NULL);
				//printf("Elapsed time for %i threads : %f sec\n",max_threads, (float) (((double) ((end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec))) / ((double) 1000000)));
				double current_usec = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
				float current_sec   =current_usec / 1000000.0f;
				float multiplier = 1.0f/(1.0f-((float)values_left_to_get)/((float)nr_of_patches));
				printf("%6.2f %c: Time spent: %6.2f Estimated time left: %6.2f seconds\n",(1-((float)values_left_to_get)/((float)nr_of_patches))*100,'%',current_sec,(multiplier-1)*current_sec);
			}
			close(newsockfd);
		}
		gettimeofday(&end, NULL);
		printf("Elapsed time for %i threads : %f sec\n",max_threads, (float) (((double) ((end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec))) / ((double) 1000000)));
		
		float best_atm_val = 99999;
		int best_atm_nr = -1;
		float best_alpha = 0;
		for(int i = 1; i < nr_of_patches+1; i++)
		{
			added_columns[nr_columns] = i;
			alpha[nr_columns] = 0;
			float err = all_results[i];
			//printf("Error for %i: %f\n",i,err);
			if(err < best_atm_val)
			{
				best_atm_val = err;
				best_atm_nr = i;
				best_alpha = alpha[nr_columns];
			}
		}
		added_columns[nr_columns] = best_atm_nr;
		alpha[nr_columns] = best_alpha;
		printf("=====================================================================================\nbest_atm_nr = %i ",best_atm_nr);
		{
			int i = added_columns[nr_columns];
			char filename_bin[256];
			sprintf(filename_bin, "%s_%i.results",responses_path, i);
			responses[i] = new float[classifier_responses_saved];
			ifstream::pos_type fsize_bin;
			ifstream file_bin (filename_bin, ios::in|ios::binary|ios::ate);
			if (file_bin.is_open())
			{
				fsize_bin = file_bin.tellg();
				file_bin.seekg (0, ios::beg);
				file_bin.read ((char *)responses[i], fsize_bin);
				file_bin.close();
			}
			else{printf("couldnt open %s \n",filename_bin);}
		}
		float err = gradient_decent_optimize(responses,classifier_responses_saved, added_columns, alpha, nr_columns+1);
		printf("error: %f\n=====================================================================================\n",err);
		nr_columns++;
		nr_classifiers = nr_columns;
		delete all_results;
		char filename[256];
		sprintf(filename, "%s_%i",save_path,nr_classifiers);
		printf("filename = %s\n",filename);
		save(filename);
	}
	usleep(2000000);
	close(sockfd);
}

BoostedClassifierIV::~BoostedClassifierIV() {
	// TODO Auto-generated destructor stub
}

FeatureResponse * BoostedClassifierIV::evaluate(IntegralImageFeature * iifeat,float w, float h,float item_size){
	float total = 0;

	for(int i = 0; i < nr_classifiers; i++)
	{
		int classifier_number = used_classifiers[i] - 1;
		FeatureResponse * retval = classifiers[classifier_number]->evaluate(iifeat, w, h, item_size);
		if(retval != NULL){
			total += alpha_weight[i]*retval->response[0];
			delete retval;
		}
	}
	float * tmp = new float[1];
	if(total < 0){total = 0;}
	tmp[0] = total;
	return new FeatureResponse(tmp,1);

};


ifstream::pos_type fsize;
//char * memblock;

void BoostedClassifierIV::save(char * path){
	printf("Saving classifier to path:%s\n",path);

	for(int i = 0; i < nr_classifiers; i++)
	{
		char filename_parts[256];
		sprintf(filename_parts, "%s.part%i", path,i);
		//printf("i = %i\n",i);
		printf("used_classifiers[%i] = %i\n",i,used_classifiers[i]);
		classifiers[used_classifiers[i]-1]->save(filename_parts);
		printf("weight: %f\n",alpha_weight[i]);

	}
	printf("===============================================\nout alpha:");
	for(int i = 0; i < nr_classifiers; i++)
	{printf("%f , ",alpha_weight[i]);}
	printf("\n");
	char filename_bin[256];
	sprintf(filename_bin, "%s.bin", path);
	ofstream outfile (filename_bin,ofstream::binary);
	outfile.write ((char *)alpha_weight,nr_classifiers*4);
	//delete[] data;
	outfile.close();


};



bool BoostedClassifierIV::load(char * path){
	printf("loading classifier from path:%s\n",path);
	bool loop = true;
	Classifier ** list_of_classifiers = new Classifier*[100000];
	int nr_of_patches = 0;
	for(int i = 0; loop ; i++)
	{
		Classifier * classifier = new SVMClassifier();
		char filename_parts[256];
		sprintf(filename_parts, "%s.part%i", path,i);
		loop = classifier->load(filename_parts);
		if(loop)
		{
			list_of_classifiers[i] = classifier;
			nr_of_patches = i+1;
			//printf("==================\n");
		}
		//else{printf("loaded all classifiers\n");}
	}
	printf("loaded %i parts\n",nr_of_patches);
	char filename_bin[256];
	sprintf(filename_bin, "%s.bin", path);
	ifstream file (filename_bin, ios::in|ios::binary|ios::ate);
	if (file.is_open())
	{
		fsize = file.tellg();
		float * alpha = new float[nr_of_patches];
		int * used = new int[nr_of_patches];
		file.seekg (0, ios::beg);
		file.read ((char *)alpha, fsize);
		file.close();
		cout << "the complete file content is in memory\n";
		printf("in: ");
		for(int i = 0; i < nr_of_patches; i++)
		{
			printf("%f , ",alpha[i]);
			used[i]=i+1;
		}
		printf("\n");
		classifiers = list_of_classifiers;
		alpha_weight = alpha;
		nr_classifiers = nr_of_patches;
		used_classifiers = used;
		return true;
	}
	else cout << "Unable to open data file\n";

	return false;
};

FeatureResponse * BoostedClassifierIV::evaluate(FeatureResponse * data){
	return NULL;
};

void BoostedClassifierIV::train(FeatureResponse ** target, FeatureResponse ** data,float * data_weights, int nr_data){

};

};
